package com.example.shutdown;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Calendar;
import java.util.TimeZone;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.ContentObserver;
import android.media.AudioManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.SystemClock;
import android.util.Log;
import android.provider.Settings;
import org.litepal.crud.DataSupport;
import java.text.SimpleDateFormat;

/**
 * 
 * @author jackly
 * @Date 2011-10-9 16:55:52
 * 
 */

@TargetApi(23)
public class AlarmService extends Service {
	private final static String TAG = "yu_AlarmService";
	private final static String IS_SAVE_UPTIME = "is_save_uptime";
	private final static String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
	private final static String set_alarm_time_path = "/sys/bus/i2c/drivers/rtc_hym8563/set_alarm_time";
	private final static String set_alarm_mode_path = "/sys/bus/i2c/drivers/rtc_hym8563/set_alarm_mode";
	private final static int POWER_OFF_CODE = 0;
	private final static int REBOOT_CODE = 1;
	private final static int POWER_OFF_UPDATE_CODE = 2;
	private final static int POWER_ON_UPDATE_CODE = 3;
	private Context context;
	private Handler mHandler;
	private int offHour = -1;
	private int offMin = -1;
	private int onHour = -1;
	private int onMin = -1;
	private int rebootHour = -1;
	private int rebootMin = -1;
	private int offWeek = -1;
	private int onWeek = -1;
	private boolean rebootEnable;
	private boolean powerOnEnable;
	private boolean powerOffEnable;
	private int todayWeek, nowHour, nowMin, nowSec;

	private final static int MSG_SYSTEM_POWEROFF = 1;
	private final static int MSG_SYSTEM_REBOOT = 2;
	private SharedPreferences sharedPreferences;
	private boolean isSaveUptime;
	private AlarmManager alarmManager;
	private boolean updateBootTime;
	private boolean haveNextOnPlan;
	private UptimeThread uptimeThread;

	public void setString(String path, String value) {
		File modefile = new File(path);
		if (modefile.exists()) {
			try {
				RandomAccessFile file = new RandomAccessFile(path, "rw");
				file.write(value.getBytes());
				file.close();
				Log.d(TAG, "set value  = " + value);
			} catch (IOException re) {
				Log.e(TAG, re.toString());
			} catch (NumberFormatException re) {
				Log.e(TAG, re.toString());
			}
		}
	}

	private static String getString(String path) {
		String prop = "0";
		try {
			BufferedReader reader = new BufferedReader(new FileReader(path));
			prop = reader.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return prop;
	}

	private void setRtcTime(String time) {
		File rf = new File(set_alarm_time_path);
		if (rf.exists()) {
			try {
				RandomAccessFile file = new RandomAccessFile(
						set_alarm_time_path, "rw");
				file.write(time.getBytes());
				file.close();
				Log.d(TAG, "SetRtcTime:  " + time);
			} catch (IOException re) {
				Log.e(TAG, "SetRtcTime IO Exception");
			} catch (NumberFormatException re) {
				Log.e(TAG, "SetRtcTime NumberFormatException");
			}
		} else {
			Log.d(TAG, "SetRtcmode failed!! path =  " + set_alarm_time_path
					+ " not exists!");
		}
	}

	private void setRtcmode(int mode) {
		File modefile = new File(set_alarm_mode_path);
		if (modefile.exists()) {
			try {
				RandomAccessFile file = new RandomAccessFile(
						set_alarm_mode_path, "rw");
				String m = String.valueOf(mode);
				file.write(m.getBytes());
				file.close();
				Log.d(TAG, "SetRtcmode AIE = " + mode);
			} catch (IOException re) {
				Log.e(TAG, "SetRtcmode IO Exception");
			} catch (NumberFormatException re) {
				Log.e(TAG, "SetRtcmode NumberFormatException");
			}
		} else {
			Log.d(TAG, "SetRtcmode failed!!! path = " + set_alarm_mode_path);
		}
	}

	@Override
	public IBinder onBind(Intent arg0) {

		return null;
	}

	/**
	 * lzp check is playing now.
	 */
	private boolean isPlaying() {
		boolean ret = false;
		final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
		if (am.isMusicActive()) {
			ret = true;
			Log.v(TAG, "*******isPlaying now...*********");
		}
		return ret;
	}

	// Add by jackly 2020-3-26 For History Uptime
	private class UptimeThread extends Thread {
		@Override
		public void run() {
			super.run();
			while (isSaveUptime) {
				long shutdownTimeMillis = System.currentTimeMillis();
				long upTimeMillis = SystemClock.elapsedRealtime();
				long bootupTimeMillis = shutdownTimeMillis - upTimeMillis;
				long uptimeSeconds = upTimeMillis / 1000 == 0 ? 1
						: upTimeMillis / 1000;
				Settings.System.putString(context.getContentResolver(),
						"last_boot_time", getFormatDateTime(bootupTimeMillis));
				Settings.System
						.putString(context.getContentResolver(),
								"last_shut_time",
								getFormatDateTime(shutdownTimeMillis));
				Settings.System.putString(context.getContentResolver(),
						"last_up_time", updateTimes());
				Settings.System.putString(context.getContentResolver(),
						"last_uptime_seconds", String.valueOf(uptimeSeconds));
				Log.d(TAG, "--------upTimeMillis------");
				try {
					Thread.sleep(10 * 1000);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	private ContentObserver uptimeObserver = new ContentObserver(mHandler) {
		@Override
		public void onChange(boolean selfChange) {
			isSaveUptime = Settings.System.getInt(getContentResolver(),
					IS_SAVE_UPTIME, 0) == 1;
			if (isSaveUptime) {
				uptimeThread = new UptimeThread();
				uptimeThread.start();
			} else {
				uptimeThread = null;
			}
		}
	};

	public void onCreate() {
		Log.d(TAG, "------onCreate------");
		context = this;
		mHandler = new Handler();
		getContentResolver().registerContentObserver(Settings.System.getUriFor(IS_SAVE_UPTIME), true,uptimeObserver);
		alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
		sharedPreferences = getSharedPreferences("zhao", MODE_PRIVATE);
		isSaveUptime = Settings.System.getInt(getContentResolver(),IS_SAVE_UPTIME, 0) == 1;
		if (isSaveUptime) {
			uptimeThread = new UptimeThread();
			uptimeThread.start();
		}
		super.onCreate();
	}

	private String updateTimes() {
		long at = SystemClock.uptimeMillis() / 1000;
		long ut = SystemClock.elapsedRealtime() / 1000;
		if (ut == 0) {
			ut = 1;
		}
		return convert(ut);
	}

	private String pad(int n) {
		if (n >= 10) {
			return String.valueOf(n);
		} else {
			return "0" + String.valueOf(n);
		}
	}

	private String convert(long t) {
		int s = (int) (t % 60);
		int m = (int) ((t / 60) % 60);
		int h = (int) ((t / 3600));

		return h + ":" + pad(m) + ":" + pad(s);
	}

	private String getFormatDateTime(long timeMillis) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return sdf.format(timeMillis);
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG, "======= onStartCommand =========");

		setPowerManagerTime();
		return super.onStartCommand(intent, flags, startId);
	}
	private void setPowerManagerTime() {
		Calendar calendar = Calendar.getInstance();
		nowHour = calendar.get(Calendar.HOUR_OF_DAY);
		nowMin = calendar.get(Calendar.MINUTE);
		nowSec = calendar.get(Calendar.SECOND);
		todayWeek = calendar.get(Calendar.DAY_OF_WEEK);
		updateBootTime = false;
		haveNextOnPlan = false;
		powerOnEnable = false;
		powerOffEnable = false;
		rebootEnable = sharedPreferences.getBoolean("reboot_enable", false);
		rebootHour = sharedPreferences.getInt("reboot_hour", 22);
		rebootMin = sharedPreferences.getInt("reboot_min", 0);
		
		List<PowerPlan> todayPowerPlans = DataSupport.where("week = ?",String.valueOf(todayWeek)).find(PowerPlan.class);
		if(todayPowerPlans.size() > 0){
			PowerPlan powerPlan = todayPowerPlans.get(0);
			powerOffEnable = powerPlan.isPowerOffEnable();
			offWeek = todayWeek;
			offHour = powerPlan.getOffHour();
			offMin = powerPlan.getOffMin();
		}
		List<PowerPlan> enablePlans = DataSupport.where("powerOnEnable = ?", "1")
				.order("week asc")// asc---正序排列, desc--倒序排列
				.find(PowerPlan.class);
		List<Integer> enableWeeks = new ArrayList<Integer>();

		for (PowerPlan powerPlan : enablePlans) {
			enableWeeks.add(powerPlan.getWeek());
		}

		if (enablePlans.size() == 0) {
			powerOnEnable = false;
		} else {
			// Not have today power on time, so add the today Week to the list
			// for finding the Avaiable power time
			if (!enableWeeks.contains(todayWeek)) {
				enableWeeks.add(todayWeek);
				Collections.sort(enableWeeks);
			} else {
				for (PowerPlan powerPlan : enablePlans) {
					if (todayWeek == powerPlan.getWeek()) {
						powerOnEnable = true;
						onWeek = todayWeek;
						onHour = powerPlan.getOnHour();
						onMin = powerPlan.getOnMin();
						if (isToday(onHour, onMin)) {
							updateBootTime = true;
							haveNextOnPlan = true;
						}
						if(powerOffEnable && onHour == offHour && onMin == offMin && onWeek == offWeek){
							haveNextOnPlan = false;
							updateBootTime = false;
						}
						break;
					}
				}
			}

			if (!haveNextOnPlan) {
				for (int i = 0; i < enableWeeks.size(); i++) {
					if (enableWeeks.get(i) == todayWeek) {
						if (i != enableWeeks.size() - 1) {
							onWeek = enableWeeks.get(i + 1);
							Log.d(TAG,
									"------Found the Boot time is this week:"
											+ getWeekString(onWeek));
						} else {
							onWeek = enableWeeks.get(0);
							Log.d(TAG,
									"------Found the Boot time is next week:"
											+ getWeekString(onWeek));
						}
						break;
					}
				}
				for (PowerPlan powerPlan : enablePlans) {
					if (powerPlan.getWeek() == onWeek) {
						onHour = powerPlan.getOnHour();
						onMin = powerPlan.getOnMin();
						onWeek = powerPlan.getWeek();
						powerOnEnable = true;
						haveNextOnPlan = true;
						break;
					}
				}
			}
		}
		if (powerOnEnable) {
			setPowerOnTime(onHour, onMin, onWeek);
			setRtcmode(1);
		} else {
			setRtcmode(0);
		}
		Intent onPlanIntent = new Intent("rk.android.setturnontime.action");
		onPlanIntent.putExtra("onHour", String.valueOf(onHour));
		onPlanIntent.putExtra("onMin", String.valueOf(onMin));
		onPlanIntent.putExtra("onWeek", String.valueOf(onWeek));
		onPlanIntent.putExtra("enable", powerOnEnable);
		sendBroadcast(onPlanIntent);


		if (updateBootTime) {
			Intent intent = new Intent("com.itemp.poweron.update");
			intent.setClass(context, AlarmReceiver.class);
			PendingIntent pi = PendingIntent.getBroadcast(context,
					POWER_ON_UPDATE_CODE, intent,
					PendingIntent.FLAG_CANCEL_CURRENT);
			calendar.set(Calendar.HOUR_OF_DAY, onHour);
			calendar.set(Calendar.MINUTE, onMin);
			calendar.set(Calendar.SECOND, 59);
			alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(),pi);
			calendar.setTimeInMillis(System.currentTimeMillis());
		} else {
			Intent intent = new Intent("com.itemp.poweron.update");
			intent.setClass(context, AlarmReceiver.class);
			PendingIntent pi = PendingIntent.getBroadcast(context,
					POWER_ON_UPDATE_CODE, intent, PendingIntent.FLAG_NO_CREATE);
			if (pi != null) {
				alarmManager.cancel(pi);
			}
		}
		setPoweroffTime(offHour, offMin, powerOffEnable);
		setRebootTime(rebootHour, rebootMin, rebootEnable);
		Log.d(TAG, "-------PowerOn enable = " + powerOnEnable);
		Log.d(TAG, "-------PowerOn week = " + getWeekString(onWeek));
		Log.d(TAG, "-------PowerOn time = " + onHour + ":" + onMin);
		Log.d(TAG, "-------PowerOff enable = " + powerOffEnable);
		Log.d(TAG, "-------PowerOff week = " + getWeekString(offWeek));
		Log.d(TAG, "-------PowerOff time = " + offHour + ":" + offMin);
		Log.d(TAG, "-------Reboot enable = " + rebootEnable);
		Log.d(TAG, "-------Reboot time = " + rebootHour + ":" + rebootMin);
	}

	/* 周日,周一,周二,周三,周四,周五,周六 ************ */
	/* 1, 2, 3, 4, 5, 6, 7 ***android** */
	/* 0, 1, 2, 3, 4, 5, 6 ***kernel** */
	private void setPowerOnTime(int h, int m, int w) {
		Calendar calendar = Calendar.getInstance();
		// 设置日历的时间，主要是让日历的年月日和当前同步
		calendar.setTimeInMillis(System.currentTimeMillis());
		// 设置日历的小时和分钟
		calendar.set(Calendar.HOUR_OF_DAY, h);
		calendar.set(Calendar.MINUTE, m);
		calendar.set(Calendar.DAY_OF_WEEK, w);
		// 将秒和毫秒设置为0
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		Log.d(TAG, "selectTimetime = " + calendar.getTime());
		// 根据时区转换时间为格林尼治时间
		long selectTime = calendar.getTimeInMillis()
				- TimeZone.getDefault().getRawOffset();
		calendar.setTimeInMillis(selectTime);
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int min = calendar.get(Calendar.MINUTE);
		int week = calendar.get(Calendar.DAY_OF_WEEK);
		week--;
		Log.d(TAG, "----selectTime---" + h + ":" + m + "---week:" + w);
		Log.d(TAG, "----setRTCTime---" + hour + ":" + min + "---week:" + week);
		setRtcTime(formatalarmTime(hour, min, week));
	}

	private String formatalarmTime(int h, int m, int week) {
		StringBuffer buf = new StringBuffer();
		if (h < 10) {
			buf.append("0" + h);
		} else {
			buf.append(h);
		}
		if (m < 10) {
			buf.append("0" + m);
		} else {
			buf.append(m);
		}
		buf.append(week);
		Log.d(TAG, "-------formatalarmTime---------" + buf.toString());
		return buf.toString();
	}

	private String getWeekString(int week) {
		switch (week) {
		case 1:
			return "Sunday";
		case 2:
			return "Monday";
		case 3:
			return "Tuesday";
		case 4:
			return "Wednesday";
		case 5:
			return "Thursday";
		case 6:
			return "Friday";
		case 7:
			return "Saturday";
		default:
			return "";
		}
	}

	private boolean isToday(int planHour, int planMin) {
		if (planHour > nowHour) {
			return true;
		} else if (planHour == nowHour) {
			if (planMin > nowMin) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	private void setPoweroffTime(int hour, int min, boolean enable) {
		Calendar calendar = Calendar.getInstance();
		nowHour = calendar.get(Calendar.HOUR_OF_DAY);
		nowMin = calendar.get(Calendar.MINUTE);
		Log.d(TAG, "----setPoweroffTime---" + hour + ":" + min
				+ "---Current Time is " + nowHour + ":" + nowMin);
		Intent powerOffIntent = new Intent("com.itemp.poweroff");
		powerOffIntent.setClass(context, AlarmReceiver.class);
		PendingIntent powerOffPi = PendingIntent.getBroadcast(context,
				POWER_OFF_CODE, powerOffIntent,
				PendingIntent.FLAG_CANCEL_CURRENT);
		if (enable && isToday(hour, min)) {
			calendar.set(Calendar.HOUR_OF_DAY, hour);
			calendar.set(Calendar.MINUTE, min);
			calendar.set(Calendar.SECOND, 10);
			Log.d(TAG, "----Power off time is " + hour + ":" + min);
			alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(),
					powerOffPi);
			// alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
			// calendar.getTimeInMillis(), powerOffPi);
			calendar.setTimeInMillis(System.currentTimeMillis());
		} else {
			PendingIntent cancelPowerOffPi = PendingIntent.getBroadcast(
					context, POWER_OFF_CODE, powerOffIntent,
					PendingIntent.FLAG_NO_CREATE);
			if (cancelPowerOffPi != null) {
				alarmManager.cancel(powerOffPi);
			}
			Intent intent = new Intent("com.itemp.poweroff.update");
			intent.setClass(context, AlarmReceiver.class);
			PendingIntent pi = PendingIntent.getBroadcast(context,
					POWER_OFF_UPDATE_CODE, intent,
					PendingIntent.FLAG_CANCEL_CURRENT);
			calendar.set(Calendar.HOUR_OF_DAY, 23);
			calendar.set(Calendar.MINUTE, 59);
			calendar.set(Calendar.SECOND, 59);
			Log.d(TAG, "----power off time is not today or disabled " + hour
					+ ":" + min);
			alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(),
					pi);
			// alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
			// calendar.getTimeInMillis(), pi);
			calendar.setTimeInMillis(System.currentTimeMillis());
		}
	}

	private void setRebootTime(int hour, int min, boolean enable) {
		Calendar calendar = Calendar.getInstance();
		nowHour = calendar.get(Calendar.HOUR_OF_DAY);
		nowMin = calendar.get(Calendar.MINUTE);
		Log.d(TAG, "--setRebootTime--Current Time is " + nowHour + ":" + nowMin);
		Intent rebootIntent = new Intent("com.itemp.reboot");
		rebootIntent.setClass(context, AlarmReceiver.class);
		PendingIntent rebootPi = PendingIntent.getBroadcast(context,
				REBOOT_CODE, rebootIntent, PendingIntent.FLAG_CANCEL_CURRENT);
		if (enable && isToday(hour, min)) {
			calendar.set(Calendar.HOUR_OF_DAY, hour);
			calendar.set(Calendar.MINUTE, min);
			calendar.set(Calendar.SECOND, 15);
			Log.d(TAG, "----Reboot time is " + hour + ":" + min);
			alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(),
					rebootPi);
			// alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
			// calendar.getTimeInMillis(), rebootPi);
			calendar.setTimeInMillis(System.currentTimeMillis());
		} else {
			PendingIntent cancelRebootPi = PendingIntent.getBroadcast(context,
					REBOOT_CODE, rebootIntent, PendingIntent.FLAG_NO_CREATE);
			if (cancelRebootPi != null) {
				alarmManager.cancel(cancelRebootPi);
			}
			alarmManager.cancel(rebootPi);
//			Intent intent = new Intent("com.itemp.poweroff.update");
//			intent.setClass(context, AlarmReceiver.class);
//			PendingIntent pi = PendingIntent.getBroadcast(context,
//					POWER_OFF_UPDATE_CODE, intent,
//					PendingIntent.FLAG_CANCEL_CURRENT);
//			calendar.set(Calendar.HOUR_OF_DAY, 23);
//			calendar.set(Calendar.MINUTE, 59);
//			calendar.set(Calendar.SECOND, 59);
//			Log.d(TAG, "----reboot time is not today or disabled " + hour + ":"
//					+ min);
//			alarmManager.setExact(AlarmManager.RTC, calendar.getTimeInMillis(),
//					pi);
//			calendar.setTimeInMillis(System.currentTimeMillis());
		}
	}

	@Override
	public void onStart(Intent intent, int startId) {
		Log.d(TAG, "======onStart====");
	}

	@Override
	public void onDestroy() {
		Log.d(TAG, "======onDestroy====");
		super.onDestroy();
		getContentResolver().unregisterContentObserver(uptimeObserver);
	}

}
